package cn.wzy.service.impl;

import cn.wzy.config.RegisterNoticeRabbitmqConfig;
import cn.wzy.dto.RegisterDTO;
import cn.wzy.dto.RegisterNoticeDto;
import cn.wzy.dto.WxBindDTO;
import cn.wzy.enums.BaseConstants;
import cn.wzy.enums.WxConstants;
import cn.wzy.mapper.LogininfoMapper;
import cn.wzy.mapper.UserMapper;
import cn.wzy.mapper.WxuserMapper;
import cn.wzy.pojo.Logininfo;
import cn.wzy.pojo.User;
import cn.wzy.pojo.Wxuser;
import cn.wzy.results.ResponseResult;
import cn.wzy.service.UserService;
import cn.wzy.utils.BeanCopyUtils;
import cn.wzy.utils.HttpUtil;
import cn.wzy.utils.MD5Utils;
import cn.wzy.utils.RedisCache;
import cn.wzy.vo.GoPageVo;
import cn.wzy.vo.PageVo;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * (User)表服务实现类
 *
 * @author makejava
 * @since 2023-02-06 16:25:41
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    private RedisCache redisCache;
    @Resource
    private LogininfoMapper logininfoMapper;
    @Resource
    private RabbitTemplate rabbitTemplate;
    @Resource
    private WxuserMapper wxuserMapper;
    @Resource
    private UserMapper userMapper;
 public ResponseResult getUserPage(GoPageVo goPageVo) {
        Page<User> page = new Page<>(goPageVo.getPageIndex(),goPageVo.getPageSize());
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        if (goPageVo.getKeyword()!=null && !"".equals(goPageVo.getKeyword())){
            queryWrapper.like(User::getUsername,goPageVo.getKeyword());
        }
        List<User> productTypes = page(page, queryWrapper).getRecords();
        PageVo pageVo = new PageVo(productTypes, page.getTotal(), goPageVo.getPageSize());
        return ResponseResult.okResult(pageVo);
    }

    @Override
    public ResponseResult saveUser(User user) {
        //        判断是否id存在，操作类型
        if (Objects.isNull(user.getId())){
//            添加操作
            save(user);
            return ResponseResult.okResult();
        }else {
//            修改操作
            updateById(user);
            return ResponseResult.okResult();
        }
    }

    @Override
    public ResponseResult deleteUser(Long id) {
        removeById(id);
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult deleteUserList(List<Long> ids) {
       removeByIds(ids);
       return ResponseResult.okResult();
    }

    /*
    * 注册
    * */
    @Transactional
    @Override
    public ResponseResult register(RegisterDTO registerDTO) {
//     校验验证码和密码
//        校验手机号和图片验证码
        if (StringUtils.isBlank(registerDTO.getMobile())
                || StringUtils.isBlank(registerDTO.getImageCode())
                || StringUtils.isBlank(registerDTO.getImageCodeKey())
                || StringUtils.isBlank(registerDTO.getUsername())
                || StringUtils.isBlank(registerDTO.getMobileCode())
                || StringUtils.isBlank(registerDTO.getPassword())
                || StringUtils.isBlank(registerDTO.getEmail())
                || StringUtils.isBlank(registerDTO.getPasswordTure())) {
            return ResponseResult.errorResult(201, "参数错误，请重新输入！");
        }
        String imgCode = redisCache.getCacheObject(registerDTO.getImageCodeKey());
        if (StringUtils.isBlank(imgCode)) {
            return ResponseResult.errorResult(202, "图片验证码失效，请重新刷新验证码");
        }
        if (!imgCode.equalsIgnoreCase(registerDTO.getImageCode())) {
            return ResponseResult.errorResult(203, "图片验证码输入错误，请重新输入");
        }
//        校验密码是否一致
        if (!registerDTO.getPassword().equals(registerDTO.getPasswordTure())){
            return ResponseResult.errorResult(204,"密码不一致!");
        }
//        校验手机验证码
        String  registerCode = redisCache.getCacheObject(BaseConstants.RedisContants.REGISTER_SMS_CODE + registerDTO.getMobile());
        if (StringUtils.isBlank(registerCode)){
            return ResponseResult.errorResult(205,"手机验证码已过期，请重新发送");
        }
        if (!registerCode.equals(registerDTO.getMobileCode())){
            return ResponseResult.errorResult(206,"手机验证码输入错误！");
        }
//        校验手机是否存在
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getPhone,registerDTO.getMobile());
        User one = getOne(queryWrapper);
        if (Objects.nonNull(one)){
            return ResponseResult.errorResult(207,"手机号已注册！");
        }
//        检验用户名存在
        queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername,registerDTO.getUsername());
        User user = getOne(queryWrapper);
        if (Objects.nonNull(user)){
            return ResponseResult.errorResult(208,"用户名已存在");
        }
//        设置盐值在密码加密
        String salt = UUID.randomUUID().toString().replaceAll("-","");
        String password = MD5Utils.encrypByMd5(registerDTO.getPassword() + salt);
//        保存到数据库中
        saveLoginUser(registerDTO, salt, password);

//        发送短信或者邮箱
        RegisterNoticeDto noticeDto = new RegisterNoticeDto(registerDTO.getMobile()+"/"+registerDTO.getEmail(), "你已经成功注册荣车宝");
        rabbitTemplate.convertAndSend(RegisterNoticeRabbitmqConfig.EXCHANGE_TOPICS_INFORM,"inform.sms.email",noticeDto);
        return ResponseResult.okResult();
    }


    /*
    * wx绑定
    * */
    @Transactional
    @Override
    public ResponseResult bindWechat(WxBindDTO wxBindDTO) {
//        数据非空判断
        if (StringUtils.isBlank(wxBindDTO.getPhone())
                ||StringUtils.isBlank(wxBindDTO.getAccessToken())
                ||StringUtils.isBlank(wxBindDTO.getOpenid())
                ||StringUtils.isBlank(wxBindDTO.getVerifyCode())){
            return ResponseResult.errorResult(400,"参数错误！");
        }
//        验证码判断
        String  code = redisCache.getCacheObject(BaseConstants.RedisContants.WX_SMS_BIND_CODE + wxBindDTO.getPhone());
        if (StringUtils.isBlank(code)){
            return ResponseResult.errorResult(401,"验证码已过期");
        }
        if (!code.equals(wxBindDTO.getVerifyCode())){
            return ResponseResult.errorResult(402,"验证码输入错误！");
        }
//        从wx官方获取到wx用户详情
        String wxUserStr = WxConstants.GET_USER_URL.replace("ACCESS_TOKEN", wxBindDTO.getAccessToken()).
                replace("OPENID", wxBindDTO.getOpenid());
        String wxUser = HttpUtil.httpGet(wxUserStr);
//        转为wx对象
//        转成json
        JSONObject wxUserObj = JSONObject.parseObject(wxUser);
//        logininfo
        Logininfo logininfo = null;
//        判断手机号是否存在
        User user = userMapper.selectOne( new LambdaQueryWrapper<User>().eq(User::getPhone,wxBindDTO.getPhone()));
        if (Objects.nonNull(user)){
//            手机号存在，判断是否绑定过wx
            Wxuser wxuser1 = wxuserMapper.selectOne(new LambdaQueryWrapper<Wxuser>().eq(Wxuser::getUserId,user.getId()));
            if (Objects.nonNull(wxuser1)){
//                绑定过
                ResponseResult.errorResult(403,"该手机号已绑定wx,请解绑后再试!");
            }
            logininfo = logininfoMapper.selectOne(new LambdaQueryWrapper<Logininfo>().eq(Logininfo::getPhone, wxBindDTO.getPhone()));
        }
//        手机号不存在
//          1.将logininfo，user,wxuser写到数据库并且免密登入
        String salt = UUID.randomUUID().toString();
        String password = "123456";
        Map<String, Object> map = insertUserAndLogin(wxBindDTO, wxUserObj, logininfo, user, salt, password);
        return ResponseResult.okResult(map);
    }


    private Map<String, Object> insertUserAndLogin(WxBindDTO wxBindDTO, JSONObject wxUserObj, Logininfo logininfo, User user, String salt, String password) {
        Logininfo logininfo1 = new Logininfo();
        User user1 = new User();
        if (Objects.isNull(logininfo)){
//            存库
            logininfo1 = new Logininfo();
            logininfo1.setPhone(wxBindDTO.getPhone());
            logininfo1.setType(1);
            logininfo1.setDisable(1);
            logininfo1.setUsername(UUID.randomUUID().toString());
            logininfo1.setPassword(MD5Utils.encrypByMd5(password + salt));
            logininfoMapper.insert(logininfo1);
        }
        if (Objects.isNull(user)){
            BeanUtils.copyProperties(logininfo1, user1);
            user1.setId(null);
            user1.setHeadimg((String) wxUserObj.get("headimgurl"));
            user1.setCreatetime(new Date());
            user1.setLogininfoId(logininfo1.getId());
            user1.setState(2);
            user1.setSalt(salt);
            userMapper.insert(user1);
        }
        //        转为对象
        Wxuser wxuser = new Wxuser();
        wxuser.setNickname((String) wxUserObj.get("nickname"));
        wxuser.setOpenid((String) wxUserObj.get("openid"));
        wxuser.setSex((Integer) wxUserObj.get("sex"));
        wxuser.setHeadimgurl((String) wxUserObj.get("headimgurl"));
        wxuser.setUnionid((String) wxUserObj.get("unionid"));
        wxuser.setAddress(wxUserObj.get("country")+"-"+ wxUserObj.get("province")+"-"+ wxUserObj.get("city"));
        wxuser.setUserId(user1.getId());
        wxuserMapper.insert(wxuser);
        String token = UUID.randomUUID().toString().replaceAll("-", "");
//        保存到rides
        redisCache.setCacheObject("User:" + token, logininfo1, 30, TimeUnit.MINUTES);
//        返回token和Loginininfo
        Map<String, Object> result = new HashMap<>();
        result.put("token", token);
        logininfo1.setPassword("");
        logininfo1.setSalt("");
        result.put("loginInfo", logininfo1);
        return result;
    }

    private void saveLoginUser(RegisterDTO registerDTO, String salt, String password) {
        Logininfo logininfo = new Logininfo();
        logininfo.setPassword(password);
        logininfo.setPhone(registerDTO.getMobile());
        logininfo.setSalt(salt);
        logininfo.setType(1);
        logininfo.setDisable(1);
        logininfo.setUsername(registerDTO.getUsername());
        logininfo.setEmail(registerDTO.getEmail());
        logininfoMapper.insert(logininfo);
        User user = new User();
        user.setPassword(password);
        user.setPhone(registerDTO.getMobile());
        user.setSalt(salt);
        user.setState(2);
        user.setCreatetime(new Date());
        user.setUsername(registerDTO.getUsername());
        user.setLogininfoId(logininfo.getId());
        user.setEmail(registerDTO.getEmail());
        save(user);
    }

    @Override
    public ResponseResult getUser(Long id) {
       User user = getById(id);
       return ResponseResult.okResult(user);
    }
}

